package cn.tannn.surenessdemo.user.service.impl;

import cn.hutool.core.lang.Assert;
import cn.jdevelops.entity.basics.util.UUIDUtils;
import cn.jdevelops.exception.exception.BusinessException;
import cn.tannn.surenessdemo.annotation.RebuildTree;
import cn.tannn.surenessdemo.constant.RoleConstant;
import cn.tannn.surenessdemo.controller.dto.AddAuthRoleDTO;
import cn.tannn.surenessdemo.controller.dto.UpdateAuthRoleDTO;
import cn.tannn.surenessdemo.exception.DataConflictException;
import cn.tannn.surenessdemo.user.dao.*;
import cn.tannn.surenessdemo.user.service.RoleService;
import cn.tannn.surenessdemo.user.entity.AuthResource;
import cn.tannn.surenessdemo.user.entity.AuthRole;
import cn.tannn.surenessdemo.user.entity.AuthRoleResourceBind;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * @author tomsun28
 * @date 13:10 2019-08-04
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class RoleServiceImpl implements RoleService {

    private final AuthRoleDao authRoleDao;

    private final AuthResourceDao authResourceDao;

    private final AuthUserRoleBindDao authUserRoleBindDao;

    private final AuthRoleResourceBindDao roleResourceBindDao;

    private final AuthRouteDao authRouteDaol;

    private final AuthRouteResourceBindDao authRouteResourceBindDao;

    @Override
    public boolean isRoleExist(AuthRole authRole) {
        AuthRole role = AuthRole.builder()
                .name(authRole.getName()).code(authRole.getCode()).build();
        return authRoleDao.exists(Example.of(role));
    }

    @Override
    public boolean addRole(AddAuthRoleDTO authRole) {
        AuthRole to = authRole.to(AuthRole.class);
        if (isRoleExist(to)) {
            return false;
        } else {
            if(StringUtils.isBlank(to.getCode())){
                to.setCode(UUIDUtils.getInstance().generateShortUuid());
            }
            authRoleDao.saveAndFlush(to);
            return true;
        }
    }

    @Override
    @RebuildTree
    public boolean updateRole(UpdateAuthRoleDTO authRole) {
        try {
            AuthRole byCode = authRoleDao.findByCode(authRole.getCode());
            AuthRole saveCode = authRole.to(AuthRole.class);
            Assert.notNull(byCode,() -> new BusinessException("角色不存在"));
            byCode.copy(saveCode);
            authRoleDao.saveAndFlush(byCode);
            return true;
        }catch (Exception e){
            e.printStackTrace();
        }
        return false;
    }

    @Override
    @RebuildTree
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteRole(String roleCode) {
        AuthRole byCode = authRoleDao.findByCode(roleCode);
        if( Objects.nonNull(byCode) && RoleConstant.NO_REGIST_ROLE.contains(byCode.getCode())){
            throw new BusinessException("非法删除:"+byCode.getName());
        }
        if (Objects.nonNull(byCode)) {
            // 删除角色-资源
            roleResourceBindDao.deleteRoleResourceBind(roleCode);
            // 删除角色-用户
            authUserRoleBindDao.deleteRoleResourceBind(roleCode);
            // 删除角色
            authRoleDao.deleteByCode(roleCode);
            return true;
        } else {
            return false;
        }
    }

    @Override
    public Optional<List<AuthRole>> getAllRole() {
        List<AuthRole> roleList = authRoleDao.findAll();
        return Optional.of(roleList);
    }

    @Override
    public Page<AuthRole> getPageRole(Integer currentPage, Integer pageSize) {
        PageRequest pageRequest = PageRequest.of(currentPage, pageSize);
        return authRoleDao.findAll(pageRequest);
    }


    @Override
    public List<AuthResource> getResourceOwnRole(String roleCode) {
        return authResourceDao.findRoleOwnResource(roleCode);
    }

    @Override
    public List<AuthResource> getResourceNotOwnRole(String roleCode) {
        return authResourceDao.findRoleNotOwnResource(roleCode);
    }

    @Override
    @RebuildTree
    public void authorityRoleResource(String roleCode, String resourceCode) {
        // Determine whether this resource and role exist
        if (!authRoleDao.existsByCode(roleCode) || !authResourceDao.existsByCode(resourceCode)) {
            throw new DataConflictException("角色或资源不存在");
        }
        // insert it in database, if existed the unique index will work
        AuthRoleResourceBind bind = AuthRoleResourceBind
                .builder().roleCode(roleCode).resourceCode(resourceCode).build();
        roleResourceBindDao.saveAndFlush(bind);
    }

    @Override
    public void authorityRoleRoute(String roleCode, String routeCode) {
        if (!authRoleDao.existsByCode(roleCode) ) {
            throw new DataConflictException("角色不存在");
        }
        // 根据路由查询其所有的资源，将这些资源赋予给当前角色
        List<String> resourceByRouteCode = authRouteResourceBindDao.findResourceByRouteCode(routeCode);
        List<AuthRoleResourceBind> saveBean = new ArrayList<>();
        resourceByRouteCode.forEach(it -> {
            AuthRoleResourceBind bind = AuthRoleResourceBind
                    .builder().roleCode(roleCode).resourceCode(it).build();
            saveBean.add(bind);
        });
        roleResourceBindDao.saveAll(saveBean);
    }

    @Override
    public void deleteAuthorityRoleRoute(String roleCode, String routeCode) {
        // 根据路由查询其所有的资源，将这些资源赋予给当前角色
        List<String> resourceByRouteCode = authRouteResourceBindDao.findResourceByRouteCode(routeCode);
        roleResourceBindDao.deleteRoleResourceBind(roleCode, resourceByRouteCode);
    }


    @Override
    @RebuildTree
    public void authorityRoleResource(String roleCode, List<String> resourceCode) {
        if (!authRoleDao.existsByCode(roleCode) ) {
            throw new DataConflictException("角色不存在");
        }
        resourceCode.forEach(it -> {
           try {
               // insert it in database, if existed the unique index will work
               AuthRoleResourceBind bind = AuthRoleResourceBind
                       .builder().roleCode(roleCode).resourceCode(it).build();
               roleResourceBindDao.saveAndFlush(bind);
           }catch (Exception e){
               log.error("角色资源重复",e);
           }
        });
    }

    @Override
    @RebuildTree
    public void deleteAuthorityRoleResource(String roleCode, String resourceCode) {
        roleResourceBindDao.deleteRoleResourceBind(roleCode, resourceCode);
    }

    @Override
    @RebuildTree
    public void enable(List<String> roleCodes) {
        authRoleDao.changeStatus(roleCodes,1);
    }

    @Override
    @RebuildTree
    public void disabled(List<String> roleCodes) {
        authRoleDao.changeStatus(roleCodes,0);
    }
}
